﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using K9Nano.Dependency;
using K9Nano.Domain;

namespace K9Nano.Configuration
{
    public class SettingStore : ISettingStore, IScopedDependency
    {
        private readonly IUnitOfWork _uow;

        public SettingStore(IUnitOfWork uow)
        {
            _uow = uow;
            Repository = _uow.Repository<AppSetting>();
        }

        protected IRepository<AppSetting> Repository { get; }

        public virtual async ValueTask<SettingInfo> GetSettingOrNullAsync(Guid? tenantId, Guid? userId, string name, CancellationToken cancellation = default)
        {
            using (_uow.DisableFilters())
            {
                var setting = await Repository.FirstOrDefaultAsync(x => x.Name == name
                                              && x.TenantId == tenantId
                                              && x.UserId == userId, cancellation);
                return setting == null ? null : new SettingInfo(tenantId, userId, name, setting.Value);
            }
        }

        public virtual async ValueTask DeleteAsync(SettingInfo setting, CancellationToken cancellation = default)
        {
            using (_uow.DisableFilters())
            {
                var appSetting = await Repository.FirstOrDefaultAsync(x => x.Name == setting.Name && x.TenantId == setting.TenantId && x.UserId == setting.UserId, cancellation);
                if (appSetting != null)
                {
                    await Repository.DeleteAsync(appSetting, false, cancellation: cancellation);
                }
            }
        }

        public virtual async ValueTask CreateOrUpdateAsync(SettingInfo setting, CancellationToken cancellation = default)
        {
            using (_uow.DisableFilters())
            {
                var appSetting = await Repository.FirstOrDefaultAsync(x => x.Name == setting.Name
                                                                           && x.TenantId == setting.TenantId
                                                                           && x.UserId == setting.UserId, cancellation);
                if (appSetting == null)
                {
                    appSetting = new AppSetting
                    {
                        Name = setting.Name,
                        TenantId = setting.TenantId,
                        UserId = setting.UserId,
                        Value = setting.Value
                    };
                }
                else
                {
                    appSetting.Value = setting.Value;
                }

                await Repository.InsertOrUpdateAsync(appSetting, cancellation);
            }
        }

        public virtual async ValueTask<IReadOnlyList<SettingInfo>> GetAllListAsync(Guid? tenantId, Guid? userId, CancellationToken cancellation = default)
        {
            using (_uow.DisableFilters())
            {
                var result = await Repository.GetAllListAsync(x => x.TenantId == tenantId && x.UserId == userId, cancellation);

                return result
                    .Select(x => new SettingInfo(tenantId, userId, x.Name, x.Value))
                    .ToList();
            }
        }
    }
}